package com.cst.intercepterdemo.intercepter;

import com.cst.intercepterdemo.annotation.AccessControl;
import com.cst.intercepterdemo.chain.IIntercepterChain;
import com.cst.intercepterdemo.chain.factory.IIntercepterChainFactory;
import com.cst.intercepterdemo.context.InterceptContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * <ul>
 * <li>文件名称 : com.cst.intercepterdemo.intercepter.AccessIntercepter
 * </li>
 * <li>版权所有 : 版权所有(C)2016-2020</li>
 * <li>公 司 : CST</li>
 * <li>创建时间 : 2016/12/9</li>
 * <li>修改记录 : </li>
 * </ul>
 * 类说明：
 *
 * @author Allen
 * @version 1.0
 */
public class AccessIntercepter implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(AccessIntercepter.class);

    public static final char SLASH = '/' ;

    @Autowired
    private IIntercepterChainFactory chainFactory;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest,
                             HttpServletResponse httpServletResponse, Object handler) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;

        // 查找当前handler是否有方法级别的验证注解，指定验证类
        AccessControl annotation = handlerMethod.getMethodAnnotation(AccessControl.class);
        // 无访问控制
        if(annotation==null){
            return true;
        }
        String name = annotation.value();
        String mappingPath = getRequestMapping(handlerMethod);
        String intercepterChain = StringUtils.isEmpty(name)?mappingPath : name;
        logger.info("accessControl:{},requestmapping:{}",name,mappingPath);

        IIntercepterChain chain = chainFactory.getChain(intercepterChain);
        if(chain==null){
            logger.info("not config chain:{}",intercepterChain);
            return false;
        }
        logger.info("intercept chain:{}",chain.getChainName());
        InterceptContext interceptContext = new InterceptContext(httpServletRequest);
        boolean intercept = chain.intercept(interceptContext);
        if(!intercept){
            httpServletResponse.getWriter().write(interceptContext.getErrorCode());
        }
        return intercept;
    }

    private String getRequestMapping(HandlerMethod handlerMethod){
        RequestMapping methodAnnotation = handlerMethod.getMethodAnnotation(RequestMapping.class);
        String methodMappingPath = methodAnnotation.value()[0];

        RequestMapping classRequestMapping = handlerMethod.getBeanType().getAnnotation(RequestMapping.class);
        String classMappingPath = null;
        if(classRequestMapping != null){
            classMappingPath = classRequestMapping.value()[0];
        }

        StringBuilder mappingPath = new StringBuilder();
        //类映射路径
        if(classMappingPath!=null){
            if(!isPathStartWithSlash(classMappingPath)){
                mappingPath.append(SLASH);
            }
            mappingPath.append(classMappingPath);
        }
        //方法映射路径
        boolean classPathEndWithSlash = isPathEndWithSlash(classMappingPath);
        boolean methodPathStartWithSlash = isPathStartWithSlash(methodMappingPath);

        if(classPathEndWithSlash && methodPathStartWithSlash){
            methodMappingPath = methodMappingPath.substring(0,methodMappingPath.length());
        }
        if((!classPathEndWithSlash) && (!methodPathStartWithSlash)){
            mappingPath.append(SLASH);
        }
        mappingPath.append(methodMappingPath);
        return mappingPath.toString();
    }

    private boolean isPathStartWithSlash(String path){
        return path.indexOf(SLASH)==0;
    }

    private boolean isPathEndWithSlash(String path){
        return path.indexOf(SLASH)==path.length()-1;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        //logger.info("after access control");
    }
}
